package main

import (
	"app/api"
	"app/backend"
	"context"
	"errors"
	"io/ioutil"
	"net/http"
	"os"
	"os/signal"
	"path"
	"syscall"
	"time"

	"github.com/GoAdminGroup/go-admin/modules/logger"

	_ "github.com/GoAdminGroup/go-admin/adapter/gin"              // web framework adapter
	_ "github.com/GoAdminGroup/go-admin/modules/db/drivers/mysql" // sql driver
	_ "github.com/GoAdminGroup/themes/sword"

	// ui theme
	"app/models"
	"app/pages"
	"app/tables"

	"github.com/DeanThompson/ginpprof"
	"github.com/GoAdminGroup/go-admin/engine"
	"github.com/GoAdminGroup/go-admin/template"
	"github.com/GoAdminGroup/go-admin/template/chartjs"
	bodylogger "github.com/armourstill/gin-mid/body-logger"
	"github.com/gin-gonic/gin"
	"github.com/op/go-logging"
)

var execCmd = path.Base(os.Args[0])
var log = logging.MustGetLogger(execCmd)

type logWriter struct {
	fixedLevel logging.Level
	log        *logging.Logger
}

func (w *logWriter) Write(p []byte) (n int, err error) {
	switch w.fixedLevel {
	case logging.DEBUG:
		w.log.Debug(string(p))
	case logging.INFO:
		w.log.Info(string(p))
	case logging.NOTICE:
		w.log.Notice(string(p))
	case logging.WARNING:
		w.log.Warning(string(p))
	case logging.ERROR:
		w.log.Error(string(p))
	case logging.CRITICAL:
		w.log.Critical(string(p))
	}
	return len(p), err
}

func init() {

}

func main() {
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		logger.Infof("Failed to load location:%+v", err)
	} else {
		time.Local = loc
	}
	startServer()
}

func startServer() {
	lw := &logWriter{logging.INFO, log}
	gin.SetMode(gin.DebugMode)
	gin.DefaultWriter = ioutil.Discard

	r := gin.Default()

	r.Use(gin.Recovery())
	r.Use(bodylogger.WithConfig(&bodylogger.Config{
		GinConfig: &gin.LoggerConfig{Output: lw}, WithBody: true, AfterRequest: true,
	}))

	ginpprof.Wrap(r)

	template.AddComp(chartjs.NewChart())

	eng := engine.Default()

	if err := eng.AddConfigFromJSON("./config.json").
		AddGenerators(tables.Generators).
		Use(r); err != nil {
		panic(err)
	}
	r.Static("/uploads", "./uploads")

	eng.HTML("GET", "/admin", pages.GetDashBoard)
	eng.HTMLFile("GET", "/admin/hello", "./html/hello.tmpl", map[string]interface{}{
		"msg": "Hello world",
	})

	v1 := r.Group("/api/v1")
	v1.Use(api.BasicAuth())
	api.Init(v1)

	models.Init(eng.MysqlConnection())

	srv := &http.Server{
		Addr:    ":24000",
		Handler: r,
	}

	go func() {
		if err := srv.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) {
			logger.Infof("listen: %s\n", err)
		}
	}()

	logger.Infof("Server started")
	// 启动定时任务
	backend.Init()
	backend.UpdateAccessURL(nil)

	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	logger.Infof("Shutting down server...")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := srv.Shutdown(ctx); err != nil {
		logger.Fatal("Server forced to shutdown:", err)
	}
	logger.Infof("closing database connection")
	eng.MysqlConnection().Close()

	logger.Infof("Server exiting")
}
